﻿using System;
using KWatkins.FluentMoqBuilder.Argument;

namespace KWatkins.FluentMoqBuilder
{
	internal static partial class Validate
	{
		internal static ISignedImpreciseNumber<Single> Argument(Single argument, string parameterName)
		{
			return new SingleValidation(argument, parameterName);
		}
		internal static ISignedImpreciseNumber<Double> Argument(Double argument, string parameterName)
		{
			return new DoubleValidation(argument, parameterName);
		}
	}
}

namespace KWatkins.FluentMoqBuilder.Argument
{
	internal sealed class SingleValidation 
		: ArgumentValidation<Single>, 
		ISignedImpreciseNumber<Single>,
		IUnsignedImpreciseNumber<Single>
	{
		internal SingleValidation(Single argument, string parameterName)
			: base(argument, parameterName)
		{
		}
		#region ISignedImpreciseNumber Members
		ISignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsGreaterThan(Single minimum)
		{
			if (Argument <= minimum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than ", minimum, "."));
			}
			return this;
		}
		
		ISignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsGreaterThan(Single minimum, Single tolerance)
		{
			if (Argument <= minimum - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than ", minimum, " within ", tolerance, "."));
			}
			return this;
		}

		ISignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsGreaterThanOrEqualTo(Single minimum)
		{
			if (Argument < minimum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than or equal to ", minimum, "."));
			}
			return this;
		}
		
		ISignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsGreaterThanOrEqualTo(Single minimum, Single tolerance)
		{
			if (Argument < minimum - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than or equal to ", minimum, " within ", tolerance, "."));
			}
			return this;
		}

		ISignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsLessThan(Single maximum)
		{
			if (Argument >= maximum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than ", maximum, "."));
			}
			return this;
		}
		
		ISignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsLessThan(Single maximum, Single tolerance)
		{
			if (Argument >= maximum + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than ", maximum, " within ", tolerance, "."));
			}
			return this;
		}

		ISignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsLessThanOrEqualTo(Single maximum)
		{
			if (Argument > maximum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than or equal to ", maximum, "."));
			}
			return this;
		}

		ISignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsLessThanOrEqualTo(Single maximum, Single tolerance)
		{
			if (Argument > maximum + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than or equal to ", maximum, " within ", tolerance, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsPositive()
		{
			if (Argument <= 0F)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, "Value must be positive.");
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsPositive(Single tolerance)
		{
			if (Argument <= 0F - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be positive within ", tolerance, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsNotPositive()
		{
			if (Argument > 0F)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, "Value must not be positive.");
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsNotPositive(Single tolerance)
		{
			if (Argument > 0F + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must not be positive within ", tolerance, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsNegative()
		{
			if (Argument >= 0F)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, "Value must be negative.");
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsNegative(Single tolerance)
		{
			if (Argument >= 0F + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be negative within ", tolerance, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsNotNegative()
		{
			if (Argument < 0F)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, "Value must not be negative.");
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> ISignedImpreciseNumber<Single>.IsNotNegative(Single tolerance)
		{
			if (Argument < 0F - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must not be negative within ", tolerance, "."));
			}
			return this;
		}
		#endregion
		#region IUnsignedImpreciseNumber Members
		IUnsignedImpreciseNumber<Single> IUnsignedImpreciseNumber<Single>.IsGreaterThan(Single minimum)
		{
			if (Argument <= minimum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than ", minimum, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> IUnsignedImpreciseNumber<Single>.IsGreaterThan(Single minimum, Single tolerance)
		{
			if (Argument <= minimum - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than ", minimum, " within ", tolerance, "."));
			}
			return this;
		}

		IUnsignedImpreciseNumber<Single> IUnsignedImpreciseNumber<Single>.IsGreaterThanOrEqualTo(Single minimum)
		{
			if (Argument < minimum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than or equal to ", minimum, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> IUnsignedImpreciseNumber<Single>.IsGreaterThanOrEqualTo(Single minimum, Single tolerance)
		{
			if (Argument < minimum - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than or equal to ", minimum, " within ", tolerance, "."));
			}
			return this;
		}

		IUnsignedImpreciseNumber<Single> IUnsignedImpreciseNumber<Single>.IsLessThan(Single maximum)
		{
			if (Argument >= maximum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than ", maximum, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Single> IUnsignedImpreciseNumber<Single>.IsLessThan(Single maximum, Single tolerance)
		{
			if (Argument >= maximum + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than ", maximum, " within ", tolerance, "."));
			}
			return this;
		}

		IUnsignedImpreciseNumber<Single> IUnsignedImpreciseNumber<Single>.IsLessThanOrEqualTo(Single maximum)
		{
			if (Argument > maximum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than or equal to ", maximum, "."));
			}
			return this;
		}

		IUnsignedImpreciseNumber<Single> IUnsignedImpreciseNumber<Single>.IsLessThanOrEqualTo(Single maximum, Single tolerance)
		{
			if (Argument > maximum + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than or equal to ", maximum, " within ", tolerance, "."));
			}
			return this;
		}
		#endregion
	}
	
	internal sealed class DoubleValidation 
		: ArgumentValidation<Double>, 
		ISignedImpreciseNumber<Double>,
		IUnsignedImpreciseNumber<Double>
	{
		internal DoubleValidation(Double argument, string parameterName)
			: base(argument, parameterName)
		{
		}
		#region ISignedImpreciseNumber Members
		ISignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsGreaterThan(Double minimum)
		{
			if (Argument <= minimum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than ", minimum, "."));
			}
			return this;
		}
		
		ISignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsGreaterThan(Double minimum, Double tolerance)
		{
			if (Argument <= minimum - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than ", minimum, " within ", tolerance, "."));
			}
			return this;
		}

		ISignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsGreaterThanOrEqualTo(Double minimum)
		{
			if (Argument < minimum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than or equal to ", minimum, "."));
			}
			return this;
		}
		
		ISignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsGreaterThanOrEqualTo(Double minimum, Double tolerance)
		{
			if (Argument < minimum - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than or equal to ", minimum, " within ", tolerance, "."));
			}
			return this;
		}

		ISignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsLessThan(Double maximum)
		{
			if (Argument >= maximum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than ", maximum, "."));
			}
			return this;
		}
		
		ISignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsLessThan(Double maximum, Double tolerance)
		{
			if (Argument >= maximum + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than ", maximum, " within ", tolerance, "."));
			}
			return this;
		}

		ISignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsLessThanOrEqualTo(Double maximum)
		{
			if (Argument > maximum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than or equal to ", maximum, "."));
			}
			return this;
		}

		ISignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsLessThanOrEqualTo(Double maximum, Double tolerance)
		{
			if (Argument > maximum + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than or equal to ", maximum, " within ", tolerance, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsPositive()
		{
			if (Argument <= 0D)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, "Value must be positive.");
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsPositive(Double tolerance)
		{
			if (Argument <= 0D - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be positive within ", tolerance, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsNotPositive()
		{
			if (Argument > 0D)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, "Value must not be positive.");
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsNotPositive(Double tolerance)
		{
			if (Argument > 0D + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must not be positive within ", tolerance, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsNegative()
		{
			if (Argument >= 0D)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, "Value must be negative.");
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsNegative(Double tolerance)
		{
			if (Argument >= 0D + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be negative within ", tolerance, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsNotNegative()
		{
			if (Argument < 0D)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, "Value must not be negative.");
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> ISignedImpreciseNumber<Double>.IsNotNegative(Double tolerance)
		{
			if (Argument < 0D - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must not be negative within ", tolerance, "."));
			}
			return this;
		}
		#endregion
		#region IUnsignedImpreciseNumber Members
		IUnsignedImpreciseNumber<Double> IUnsignedImpreciseNumber<Double>.IsGreaterThan(Double minimum)
		{
			if (Argument <= minimum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than ", minimum, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> IUnsignedImpreciseNumber<Double>.IsGreaterThan(Double minimum, Double tolerance)
		{
			if (Argument <= minimum - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than ", minimum, " within ", tolerance, "."));
			}
			return this;
		}

		IUnsignedImpreciseNumber<Double> IUnsignedImpreciseNumber<Double>.IsGreaterThanOrEqualTo(Double minimum)
		{
			if (Argument < minimum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than or equal to ", minimum, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> IUnsignedImpreciseNumber<Double>.IsGreaterThanOrEqualTo(Double minimum, Double tolerance)
		{
			if (Argument < minimum - Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be greater than or equal to ", minimum, " within ", tolerance, "."));
			}
			return this;
		}

		IUnsignedImpreciseNumber<Double> IUnsignedImpreciseNumber<Double>.IsLessThan(Double maximum)
		{
			if (Argument >= maximum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than ", maximum, "."));
			}
			return this;
		}
		
		IUnsignedImpreciseNumber<Double> IUnsignedImpreciseNumber<Double>.IsLessThan(Double maximum, Double tolerance)
		{
			if (Argument >= maximum + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than ", maximum, " within ", tolerance, "."));
			}
			return this;
		}

		IUnsignedImpreciseNumber<Double> IUnsignedImpreciseNumber<Double>.IsLessThanOrEqualTo(Double maximum)
		{
			if (Argument > maximum)
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than or equal to ", maximum, "."));
			}
			return this;
		}

		IUnsignedImpreciseNumber<Double> IUnsignedImpreciseNumber<Double>.IsLessThanOrEqualTo(Double maximum, Double tolerance)
		{
			if (Argument > maximum + Math.Abs(tolerance))
			{
				throw new ArgumentOutOfRangeException(ParameterName, Argument, string.Concat("Value must be less than or equal to ", maximum, " within ", tolerance, "."));
			}
			return this;
		}
		#endregion
	}
	
}
